#pragma once

#include "../../../Libs/headers.default.h"
#include "../../../Libs/headers.cv.h"
#include "Edglet.h"
#include "EnvVar.h"

namespace ideal_observer
{
	void DrawGridImage(CImg<int>& imgOutput, const CImg<int>& imgContext, int IW, int IH, int CW, int CH, int H_Extent);

	class CObjectEdglet
	{
	public:
		int x;
		int y;
		CEdglet edglet;
	};

	class CTransformation
	{
	public:
		int base_x;
		int base_y;

	public:
		CTransformation();
		CTransformation(int base_x, int base_y);
		void myInit(int base_x, int base_y);
		void Clear();
		bool InputFromStream(istream& inStream);
		void OutputToStream(ofstream& outStream) const;
	};

	class CTransformationSet
	{
	public:
		int Size;
		CSimpleTypeArray<CTransformation> List;
		CSimpleTypeArray<double> Weights;

	public:
		CTransformationSet();
		void Clear();
		void PushBack(const CTransformation& NewTransformation, double NewWeight);
		void NormalizeWeights();
		bool InputFromFile(string strFN_SrcSet);
		void OutputToFile(string strFN_DstSet);
	};

	class CFixation
	{
	public:
		int ob_x;
		int ob_y;

	public:
		CFixation();
		CFixation(int ob_x, int ob_y);
		void myInit(int ob_x, int ob_y);
		void Clear();
		bool InputFromStream(istream& inStream);
		void OutputToStream(ofstream& outStream) const;
	public:
		static bool InputListFromFile(CSimpleTypeArray<CFixation>& ListDstSet, string strFN_SrcSet);
		static void OutputListToFile(string strFN_DstSet, const CSimpleTypeArray<CFixation>& ListSrcSet);
	};

	class CFixationSet
	{
	public:
		int Size;
		CSimpleTypeArray<CFixation> List;
		//CSimpleTypeArray<double> Weights;

	public:
		CFixationSet();
		void Clear();
		void PushBack(const CFixation& NewFixation); //, double NewWeight);
		//void NormalizeWeights();
		bool InputFromFile(string strFN_SrcSet);
		void OutputToFile(string strFN_DstSet);
	};

	class CObjectTemplate
	{
	public:
		int IW, IH, IWH;
		int Amount_Edglet;
		CSimpleTypeArray<CObjectEdglet> List_Edglet;
		int xLow, yLow, xHigh, yHigh;
		int xCenter, yCenter;

	public:
		void Clear();
		void myInit(const CSimpleTypeArray<int>& matSrcObserveResult, int IW, int IH);
		void DoTransformation(
			CSimpleTypeArray<CObjectEdglet>& DstListOE,
			const CTransformation& _Transformation,
			bool fDeleteEmptyEdglets) const;
		void DoTransformation(
			CSimpleTypeArray<int>& matD,
			const CTransformation& _Transformation) const;
	};

	class CDistribution
	{
	public:
		int IE, IW, IH, IWH;
		size_t Size;
		CSimpleTypeArray<double> ce_logP;
		CSimpleTypeArray<double> ce_realP;

	public:
		CDistribution();
		CDistribution(int IW, int IH);
		void myInit(int IW, int IH);
		void ClearProb();
		void DeepClear();
	public:
		void Normalize_logP_and_Build_realP(int a_offset = -1);
	public:
		void OutputToImage(CImg<int>& imgOutput, int CW, int CH, int H_Extent, bool fDrawGrid) const;
	public:
		double* pBase_logP(int a_offset);
		double* pBase_realP(int a_offset);
		const double* pBase_logP(int a_offset) const;
		const double* pBase_realP(int a_offset) const;
	};

	class CObservation
	{
	public:
		CFixation Fixation;
		CSimpleTypeArray<int> Result;

	public:
		CObservation();
		CObservation(const CFixation& Fixation, const CSimpleTypeArray<int>& Result);
	};

	class CImageModelInstance;

	class CObservationSet
	{
	public:
		int Size;
		CSimpleTypeArray<CObservation> List;

	public:
		CObservationSet();
		void Clear();
		void NewObservation(const CObservation& NewObservation);
	protected:
		static void _MakeFN_Observation(char* DstPtrChar, const char* strPN_ObservationBase, int ObservationIndex);
	public:
		bool InputList(string strFN_SrcList, string strPN_SrcObservationBase, const CImageModelInstance& IMI);
		void OutputList(string strFN_DstList, string strPN_DstObservationBase, const CImageModelInstance& IMI) const;
	};

	class CImageModelInstance
	{
	public:
		class CAnalysisParameter
		{
		public:
			int Sampling_IterationAmount;
			double SeedAmount_Exponent;
			double SeedAmount_Coefficient;
			double T_AbandonThreshold;
			double Ra_AffectThreshold;
			double Cell_IndependentThreshold;

		public:
			CAnalysisParameter();
		};

	public:
		int IE, IW, IH, IWH;
		CObjectTemplate ObjectTemplate;
		double K1, K2, K3, Sigma, _ms;
	public:
		CAnalysisParameter AnalysisParameter;
	protected:
		CTransformation _Transformation;
		CFixation _Fixation;
	public:
		CSimpleTypeArray<double> matr_Confusion;
		CSimpleTypeArray<double> vect_EdgletPrior;
	public:
		CSimpleTypeArray<int> matPrototypeD;
	public:
		CSimpleTypeArray<double> xypOutput;

	public:
		static void InputObserveResultFromImage(
			CSimpleTypeArray<int>& matDstObserveResult,
			string strFN_SrcRGB,
			int IW, int IH, int CW, int CH);
		static void InputObserveResultFromImage(
			CSimpleTypeArray<int>& matDstObserveResult,
			const CImg<int>& imgSrcRGB,
			int IW, int IH, int CW, int CH);
	public:
		void OutputObserveResultToImage(
			CImg<int>& imgOutput,
			const CSimpleTypeArray<int>& matSrcObserveResult,
			int CW, int CH, int H_Extent, bool fDrawGrid) const;
		void OutputObserveResultToImage(
			CImg<int>& imgOutput,
			const CObservation& SrcObservation,
			int CW, int CH, int H_Extent, bool fDrawGrid) const;
	public:
		bool InputObservationFromText(
			CObservation& DstObservation,
			string strFN_SrcText) const;
		void OutputObservationToText(
			string strFN_DstText,
			const CObservation& SrcObservation) const;
	public:
		void InitObjectTemplate(string strFN_ObjectTemplate, int IW, int IH, int CW, int CH);
		void InitModelParameters(double K1, double K2, double K3, double Sigma);
		void FixProbabilitySettings();
	public:
		void InitDefaultEdgletConfusionMatrix();
		void InitDefaultEdgletPriorDistribution();
		void InitDefaultTransformationSet(CTransformationSet& DstTransformationSet);
		int InitDefaultFixationSet(CFixationSet& DstFixationSet, double FixationStrideFactor);
	public:
		bool LoadEdgletConfusionMatrix(string strFN_EdgletConfusionMatrix);
		void SaveEdgletConfusionMatrix(string strFN_EdgletConfusionMatrix);
		bool LoadEdgletPriorDistribution(string strFN_EdgletPriorDistribution);
		void SaveEdgletPriorDistribution(string strFN_EdgletPriorDistribution);
	public:
		void SetTransformation(const CTransformation& T);
		void SetFixation(const CFixation& F);
		const CTransformation& GetTransformation() const;
		const CFixation& GetFixation() const;
	protected:
		void _Refresh_PrototypeD_given_T();
	public:
		void Ouptut_PrototypeD_ToImage(CImg<int>& imgOutput, int CW, int CH, int H_Extent, bool fDrawGrid) const;
	public:
		double func_z(int dx, int dy) const;
		double func_e(int dx, int dy) const;
	public:
		double logP_Da_given_T(int a_offset, int d_a) const;
		double logP_Ra_given_Da_F(int a_offset, int r_a, int d_a) const;
	public:
		// N * E * M
		double Analyse2_given_T_RR_FF(
			CDistribution& dtrb_D_given_T,
			CDistribution& dtrb_D_given_T_RR_FF,
			CDistribution& xyD_logP_RRa_given_Da_FF,
			CSimpleTypeArray<double>& mat_logP_RRa_given_T_FF,
			const CObservationSet& ObservationSet,
			const CTransformation& T);
		void Analyse2_given_TT_RR_FF_F(
			CSimpleTypeArray<double>& DstList_P_T, int& DstBest_T, double& DstH_T,
			CSimpleTypeArray<double>& DstList_CH_F, int& DstBest_F, CFixation& DstFixation,
			const CTransformationSet& SetT, int Answer_T_Index,
			const CObservationSet& ObservationSet,
			const CFixationSet& SetF,
			ostream& oLog,
			int Output_CW, int Output_CH, int Output_H_Extent,
			string strPN_Prediction_Output);
	public:
		// N * E
		void Predict_D_given_T(CDistribution& DstDistribution) const;
		// N * E
		void Predict_R_given_obsvD_F(CDistribution& DstDistribution, const CSimpleTypeArray<int>& obsv_D) const;
		// N * E * E
		void Predict_R_given_dtrbD_F(CDistribution& DstDistribution, const CDistribution& Src_dtrbD) const;
		// N * E * E
		void Predict_R_given_T_F(CDistribution& DstDistribution) const;
	public:
		double RandomSampleObserveResult(CSimpleTypeArray<int>& DstObserveResult, const CDistribution& SrcDistribution) const;
		double RandomSample_D_given_T(CSimpleTypeArray<int>& obsv_D) const;
		double RandomSample_R_given_obsvD_F(CObservation& DstObservation, const CSimpleTypeArray<int>& obsv_D) const;
		double RandomSample_R_given_T_F(CObservation& DstObservation) const;
	};
};

using namespace ideal_observer;

